﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace DataModel
{
    public class Term : TermSet
    {
        private int depth; //how deep the term is nested, since SharePoint only lets you have terms at most 7 levels deep
        private Boolean isTaggable;
        private TermSet parent;
        private TermSet tsParent;

        public int Depth { get; set; }
        public TermSet Parent
        {
            get { return parent; }
            set {  }
        }
        public Boolean IsTaggable { get { return isTaggable; } set { isTaggable = value; } }
        public Boolean IsExpanded { get; set; }

        public PropertyCollection LocalCustomProperties { get; set; }
        public System.Collections.ObjectModel.ObservableCollection<TermLabel> Labels { get; set; }

        /// <summary>
        /// Initializes a new instance of the <see cref="Term"/> class (recommended to NOT use this constructor for general purposes).
        /// </summary>
        /// <param name="name">The name.</param>
        /// <param name="depth">The depth of the term.</param>
        /// <param name="isTaggable">if set to <c>true</c> [is taggable].</param>
        /// <param name="parent">The parent.</param>
        /// <param name="tsParent">The ts parent.</param>
        /// <param name="desc">The desc.</param>
        public Term(String name, int depth, Boolean isTaggable, TermSet parent, TermSet tsParent, String desc = "")
        {
            isRoot = false;
            this.name = name;
            Description = desc;
            this.depth = depth;
            this.isTaggable = isTaggable;
            this.parent = parent;
            this.tsParent = tsParent;
            LocalCustomProperties = new PropertyCollection();
            Labels = new System.Collections.ObjectModel.ObservableCollection<TermLabel>();
        }


        /// <summary>
        /// Adds a new term as a child to this term with the specified values. This is the preferred constructor for creating new Terms
        /// </summary>
        /// <param name="term">The term.</param>
        /// <param name="id">The identifier.</param>
        /// <param name="desc">The desc.</param>
        /// <returns></returns>
        public Term Add(String term, String id = null, String desc = "")
        {
            if (depth < 7) //because SharePoint apparently dislikes too much nesting.
            {
                Term newTerm = new Term(term, this.depth + 1, true, this, this.tsParent, desc);
                newTerm.ID = (id == null) ? GUID.get() : id;
                base.Add(newTerm);
                return newTerm;
            }
            else
            {
                return null;
            }
        }

        new private void AddRootTerm(String name, String id = null, String desc = "")
        {
            //just to hide, or "uninherit", the AddRootTerm method from TermSet
        }

        public TermSet GetContainingTermSet()
        {
            return tsParent;
        }

        /// <summary>
        /// Determines whether [is referenced by a site column].
        /// </summary>
        /// <returns></returns>
        public bool IsReferencedByASiteColumn()
        {
            bool b = false;

            foreach (SiteColumn sc in SaveFile.siteCols)
            {
                if (sc.Type == SiteColumnType.MANAGED_METADATA)
                {
                    if (sc.Tag == this) { b = true; return b; }
                }
            }
            return b;
        }

        /// <summary>
        /// Removes the references to this term from site columns in the save file.
        /// </summary>
        public void RemoveSitecolumnReferences()
        {
            foreach (SiteColumn sc in SaveFile.siteCols)
            {
                if (sc.Type == SiteColumnType.MANAGED_METADATA)
                {
                    if (sc.Tag == (this))
                    {
                        sc.Tag = null;
                    }
                }
            }
        }

        /// <summary>
        /// Gets a child term by name.
        /// </summary>
        /// <param name="name">The name.</param>
        /// <returns></returns>
        new public Term getTermByName(String name)
        {
            if (this.name == name) 
            { 
                return this; 
            }
            else
            {
                foreach (Term t in this)
                {
                    Term t2 = t.getTermByName(name);
                    if (t2 != null) { return t2; }
                }
                return null;
            }            
        }

        /// <summary>
        /// Gets a child term by identifier.
        /// </summary>
        /// <param name="id">The identifier.</param>
        /// <returns></returns>
        new public Term getTermById(String id)
        {
            if (this.ID == id)
            {
                return this;
            }
            else
            {
                foreach (Term t in this)
                {
                    Term t2 = t.getTermById(id);
                    if (t2 != null) { return t2; }
                }
                return null;
            } 
        }

    }
}
